/*
 * @(#)XfslConfigPanel.java        1.0 2000/05/09
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//PANEL DE CONFIGURACION DEL APRENDIZAJE SUPERVISADO	//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

package xfuzzy.xfsl.view;

import xfuzzy.*;
import xfuzzy.lang.*;
import xfuzzy.util.*;
import xfuzzy.xfsl.model.XfslAlgorithm;
import xfuzzy.xfsl.model.XfslAlgorithmFactory;
import xfuzzy.xfsl.model.XfslConfig;
import xfuzzy.xfsl.model.XfslEndCondition;
import xfuzzy.xfsl.model.XfslErrorFunction;
import xfuzzy.xfsl.model.XfslLog;
import xfuzzy.xfsl.model.algorithm.XfslGradientBasedAlgorithm;
import xfuzzy.xfsl.view.listener.*;

import javax.swing.*;
import java.awt.*;
import java.io.*;

/**
 * Panel de configuraci�n de la herramienta xfsl
 * 
 * @author Francisco Jos� Moreno Velo
 *
 */
public class XfslConfigPanel extends Box  {

	//----------------------------------------------------------------------------//
	//                            COSTANTES PRIVADAS                              //
	//----------------------------------------------------------------------------//

	/**
	 * C�digo asociado a la clase serializable
	 */
	private static final long serialVersionUID = 95505666603065L;

	//----------------------------------------------------------------------------//
	//                            MIEMBROS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Campos de texto
	 */
	private XTextForm text[] = new XTextForm[7];
	
	/**
	 * Botones de Load/Save de la configuraci�n
	 */
	private XCommandForm form;
	
	/**
	 * Configuraci�n mostrada
	 */
	private XfslConfig config;
	
	/**
	 * Ventana principal de la aplicaci�n
	 */
	private Xfsl xfsl;

	//----------------------------------------------------------------------------//
	//                                CONSTRUCTOR                                 //
	//----------------------------------------------------------------------------//

	/**
	 * Constructor
	 */
	public XfslConfigPanel(Xfsl xfsl) {
		super(BoxLayout.Y_AXIS);
		this.xfsl = xfsl;
		this.config = xfsl.getConfig();
		build();
	}

	//----------------------------------------------------------------------------//
	//                             M�TODOS P�BLICOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * (Des)Habilita los botones del panel
	 */
	public void setEnabled(boolean enable) {
		for(int i=0; i<text.length; i++) text[i].setLabelEnabled(enable);
		form.setEnabled(0,enable);
		form.setEnabled(1,enable);
	}

	/**
	 * Actualiza la informacion mostrada en el panel
	 */
	public void set() {
		config.modified = true;
		if(config.trainingfile != null) 
			text[0].setText(config.trainingfile.getAbsolutePath());
		else text[0].setText("");
		if(config.testfile != null)
			text[1].setText(config.testfile.getAbsolutePath());
		else text[1].setText("");
		if(config.logfile != null)
			text[2].setText(config.logfile.toString());
		else text[2].setText("");
		if(config.algorithm != null)
			text[3].setText(config.algorithm.getName());
		else text[3].setText("");
		if(config.endcondition.isOn()) text[4].setText("On");
		else text[4].setText("No End");
		text[5].setText(config.errorfunction.getName());
		if(config.areSettingsOn()) text[6].setText("On");
		else text[6].setText("Off");
		xfsl.setStatus();
		revalidate();
	}

	/**
	 *  Acci�n asociada al fichero de entrenamiento
	 */
	public void actionTrainingFile() {
		File root = config.trainingfile;
		if(root == null) root = xfsl.getWorkingDirectory();
		XFileChooser chooser = new XFileChooser(root, XFileChooser.UNSELECT);
		int returnVal = chooser.showDialog();
		if(returnVal == XFileChooser.CANCELED) return;
		if(returnVal != XFileChooser.SELECTED) config.trainingfile = null;
		else config.trainingfile = chooser.getSelectedFile();
		set();
	}

	/**
	 * Acci�n asociada al fichero de test
	 */
	public void actionTestFile() {
		File root = config.testfile;
		if(root == null) root = xfsl.getWorkingDirectory();
		XFileChooser chooser = new XFileChooser(root, XFileChooser.UNSELECT);
		int returnVal = chooser.showDialog();
		if(returnVal == XFileChooser.CANCELED) return;
		if(returnVal != XFileChooser.SELECTED) config.testfile = null;
		else config.testfile = chooser.getSelectedFile();
		set();
	}

	/**
	 * Acci�n asociada al fichero de log
	 */
	public void actionLogFile() {
		XfslLog working =  (XfslLog) config.logfile.clone();
		XfslLogDialog dialog = new XfslLogDialog(xfsl,working);
		dialog.setVisible(true);
		if(dialog.isSelected()) config.logfile = working;
		set();
	}

	/**
	 * Acci�n asociada a la condici�n de t�rmino
	 */
	public void actionEndCondition() {
		XfslEndCondition working = (XfslEndCondition) config.endcondition.clone();
		XfslEndDialog dialog = new XfslEndDialog(xfsl,working);
		dialog.setVisible(true);
		if(dialog.isSelected()) config.endcondition = working;
		set();
	}

	/**
	 * Acci�n asociada a la selecci�n de par�metros
	 */
	public void actionSettings() {
		XfslSettingsDialog dialog = new XfslSettingsDialog(xfsl);
		dialog.setVisible(true);
		set();
	}

	/**
	 * Acci�n asociada al menu de la funci�n de error
	 */
	public void actionErrorFunction() {
		String errorfunctionname[] =
		{"Mean Square Error", "Weighted Mean Square Error", "Mean Absolute Error",
				"Weighted Mean Absolute Error", "Classification Error",
				"Advanced Classification Error", "Classification Square Error"};

		JPopupMenu menu = new JPopupMenu();
		SystemModule system = xfsl.getSpec().getSystemModule();
		boolean weights = (system != null && system.getOutputs().length > 1);
		for(int i=0;i<errorfunctionname.length;i++)
			if((i!=XfslErrorFunction.W_MEAN_SQUARE_ERROR &&
					i!=XfslErrorFunction.W_MEAN_ABS_ERROR) || weights)  {
				JMenuItem item = new JMenuItem(errorfunctionname[i]);
				item.setFont(XConstants.font);
				item.addActionListener( new XfslConfigActionListener(this) );
				item.setActionCommand("ERR"+i);
				menu.add(item);
			}
		menu.show(text[5],0,text[5].getHeight());
	}

	/**
	 * Acci�n asociada a la funci�n de error
	 */
	public void actionErrorFunction(String number) {
		int index = Integer.parseInt(number);
		int code = config.errorfunction.getCode();
		XfslErrorFunction working;
		if(index == code) working = (XfslErrorFunction) config.errorfunction.clone();
		else try { working = new XfslErrorFunction(index); }
		catch(XflException ex) { return; }

		if(working.isWeighted()) {
			Variable output[] = xfsl.getSpec().getSystemModule().getOutputs();
			XfslErrorDialog dialog = new XfslErrorDialog(xfsl,output);
			if(dialog.show(working.getWeights())) {
				try { working.setWeights(dialog.getWeights()); } catch(Exception ex) {}
				config.errorfunction = working;
				set();
			}
		} else {
			config.errorfunction = working;
			set();
		}
	}

	/**
	 * Acci�n asociada al men� de algoritmo
	 */
	public void actionAlgorithm() {
		JPopupMenu menu = new JPopupMenu();
		JMenu[] fam = new JMenu[XfslAlgorithm.famname.length];
		for(int i=0; i<fam.length; i++) {
			fam[i] = new JMenu(XfslAlgorithm.famname[i]);
			fam[i].setFont(XConstants.font);
			for(int j=0; j<XfslAlgorithm.famcode[i].length; j++) {
				String label = "";
				try { label = XfslAlgorithm.getName( XfslAlgorithm.famcode[i][j] ); }
				catch(Exception ex) {}
				JMenuItem item = new JMenuItem(label);
				item.setFont(XConstants.font);
				item.addActionListener( new XfslConfigActionListener(this) );
				item.setActionCommand("ALG"+XfslAlgorithm.famcode[i][j]);
				fam[i].add(item);
			}
			menu.add(fam[i]);
		}
		menu.show(text[3],0,text[3].getHeight());
	}

	/**
	 * Acci�n asociada a la selecci�n de algoritmo
	 */
	public void actionAlgorithm(String number) {
		int index = Integer.parseInt(number);
		XfslAlgorithm working;
		if(config.algorithm != null && index == config.algorithm.getCode())
			working = (XfslAlgorithm) config.algorithm.clone();
		else try { working = XfslAlgorithmFactory.createAlgorithm(index); }
		catch(XflException ex) { return; }
		
		if(working instanceof XfslGradientBasedAlgorithm) {
			XfslGradientBasedAlgorithm gbalg = (XfslGradientBasedAlgorithm) working;
			XfslGradientBasedAlgorithmDialog dialog = new XfslGradientBasedAlgorithmDialog(xfsl,gbalg);
			dialog.setVisible(true);
			if(dialog.isSelected()) {
				config.algorithm = working;
				set();
			}			
		} else {
			XfslAlgorithmDialog dialog = new XfslAlgorithmDialog(xfsl,working);
			dialog.setVisible(true);
			if(dialog.isSelected()) {
				config.algorithm = working;
				set();
			}
		}
	}

	/**
	 * Acci�n asociada a la carga del fichero de configuraci�n
	 */
	public void actionLoadConfig() {
		File wdir = xfsl.getWorkingDirectory();
		XFileChooser chooser = new XFileChooser(wdir,XFileChooser.LOAD);
		chooser.addFileFilter(".xml","Xfuzzy Configuration Files");
		int returnVal = chooser.showDialog();
		if(returnVal != XFileChooser.SELECTED) return;
		File file = chooser.getSelectedFile();
		
		XmlParser parser = new XmlParser();
		parser.parseXML(file);
		XfslConfig xfslc = parser.getXfslConfig();
		if(xfslc != null) {
			config = xfslc;
			xfsl.setConfig(config);
			set();
		} else {
			xfsl.log(parser.getErrorMessage());
			Toolkit.getDefaultToolkit().beep();
		}
	}

	/**
	 * Accion asociada a la grabacion del fichero de configuracion
	 */
	public void actionSaveConfig() {
		File wdir = xfsl.getWorkingDirectory();
		XFileChooser chooser = new XFileChooser(wdir,XFileChooser.SAVE);
		int returnVal = chooser.showDialog();
		if(returnVal != XFileChooser.SELECTED) return;
		File file = chooser.getSelectedFile();
		
		boolean append = false;
		if(file.exists()) {
			String question[] = new String[3];
			question[0] = "File "+file.getName()+" already exists.";
			question[1] = "Do you want to overwrite this file?";
			question[2] = "(Otherwise the code will be append at the end of the file)";
			int result = XDialog.showYNQuestion(this, question);
			if(result == XDialog.CANCEL) return;
			if(result == XDialog.NO) append = true;
		}
		config.save(file,xfsl.getSpec().getName(),append);
	}
	
	//----------------------------------------------------------------------------//
	//                             M�TODOS PRIVADOS                               //
	//----------------------------------------------------------------------------//

	/**
	 * Construye el panel
	 */
	private void build() {
		XfslConfigActionListener listener = new XfslConfigActionListener(this);
		
		String lb[] =
		{ "Training File", "Test File", "Log File", "Algorithm",
				"End Condition", "Error Function", "Settings" };
		String cm[] =
		{ "TrainingFile", "TestFile", "LogFile", "Algorithm",
				"EndCondition", "ErrorFunction", "Settings" };
		for(int i=0; i<text.length; i++) {
			text[i] = new XTextForm(lb[i], listener);
			text[i].setActionCommand(cm[i]);
			text[i].setEditable(false);
		}
		XTextForm.setWidth(text);

		Box lbox = new Box(BoxLayout.Y_AXIS);
		for(int i=3; i<5; i++) lbox.add(text[i]);
		Box rbox = new Box(BoxLayout.Y_AXIS);
		for(int i=5; i<7; i++) rbox.add(text[i]);
		Box box = new Box(BoxLayout.X_AXIS);
		box.add(lbox);
		box.add(rbox);

		String label[] = { "Load Configuration", "Save Configuration" };
		String command[] = { "LoadConfig", "SaveConfig" };
		form = new XCommandForm(label,command, listener);
		form.setCommandWidth(200);

		add(new XLabel("Configuration"));
		for(int i=0; i<3; i++) add(text[i]);
		add(box);
		add(form);
	}
}

